package com.ylz.sjzx.sio.sdk.client.core.socketio;

import cn.hutool.core.util.StrUtil;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Transport;
import com.corundumstudio.socketio.ack.AckManager;
import com.corundumstudio.socketio.handler.PacketListener;
import com.corundumstudio.socketio.namespace.Namespace;
import com.corundumstudio.socketio.namespace.NamespacesHub;
import com.corundumstudio.socketio.protocol.Packet;
import com.corundumstudio.socketio.protocol.PacketType;
import com.corundumstudio.socketio.scheduler.CancelableScheduler;
import com.corundumstudio.socketio.scheduler.SchedulerKey;
import com.corundumstudio.socketio.transport.NamespaceClient;
import com.corundumstudio.socketio.transport.PollingTransport;
import com.ylz.sjzx.sio.common.core.enums.Cmd;
import com.ylz.sjzx.sio.common.core.utils.GsonUtil;
import com.ylz.sjzx.sio.sdk.client.core.SocketProcess;
import com.ylz.sjzx.sio.sdk.model.BaseSocketModel;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.List;

/**
 * @author wiqi
 * @version 1.0
 * @date 2020/12/21
 */
@Slf4j
public class ImPacketListener extends PacketListener {
    private final NamespacesHub iNamespacesHub;
    private final AckManager iAckManager;
    private final CancelableScheduler iScheduler;

    public ImPacketListener(AckManager ackManager, NamespacesHub namespacesHub, PollingTransport xhrPollingTransport,
                            CancelableScheduler scheduler) {
        super(ackManager, namespacesHub, xhrPollingTransport, scheduler);
        this.iNamespacesHub = namespacesHub;
        this.iAckManager = ackManager;
        this.iScheduler = scheduler;

    }

    @Override
    public void onPacket(Packet packet, NamespaceClient client, Transport transport) {
        if (packet.isAckRequested()) {
            this.iAckManager.initAckIndex(client.getSessionId(), packet.getAckId());
        }

        switch (packet.getType()) {
            case PING: {
                Packet outPacket = new Packet(PacketType.PONG);
                outPacket.setData(packet.getData());
                // TODO use future
                client.getBaseClient().send(outPacket, transport);

                if ("probe".equals(packet.getData())) {
                    client.getBaseClient().send(new Packet(PacketType.NOOP), Transport.POLLING);
                } else {
                    client.getBaseClient().schedulePingTimeout();
                }
                break;
            }

            case UPGRADE: {
                client.getBaseClient().schedulePingTimeout();

                SchedulerKey key = new SchedulerKey(SchedulerKey.Type.UPGRADE_TIMEOUT, client.getSessionId());
                this.iScheduler.cancel(key);

                client.getBaseClient().upgradeCurrentTransport(transport);
                break;
            }

            case MESSAGE: {
                client.getBaseClient().schedulePingTimeout();

                if (packet.getSubType() == PacketType.DISCONNECT) {
                    client.onDisconnect();
                }

                if (packet.getSubType() == PacketType.CONNECT) {
                    Namespace namespace = this.iNamespacesHub.get(packet.getNsp());
                    namespace.onConnect(client);
                    // send connect handshake packet back to client
                    client.getBaseClient().send(packet, transport);
                }

                if (packet.getSubType() == PacketType.ACK) {
                    this.iAckManager.onAck(client, packet);
                }
                if (packet.getSubType() == PacketType.BINARY_EVENT) {
                    Namespace namespace = this.iNamespacesHub.get(packet.getNsp());
                    List<Object> args = Collections.emptyList();
                    if (packet.getData() != null) {
                        args = packet.getData();
                    }
                    AckRequest ackRequest = new AckRequest(packet, client);
                    namespace.onEvent(client, packet.getName(), args, ackRequest);
                }

                if (packet.getSubType() == PacketType.EVENT) {
                    if (StrUtil.isBlank(packet.getName())) {
                        //兼容IOS bug
                        return;
                    }
                    log.debug("packet.getName(){}", packet.getName());
                    log.debug("packet.getData()(){}", GsonUtil.bean2Json(packet.getData()));
                    //重写
                    //  namespace.onEvent(client, packet.getName(), args, ackRequest);
                    //request data 转对象
                    BaseSocketModel baseSocketModel =
                            BaseSocketModel.builder().action(Cmd.valueOf(packet.getName().replace("-", "")))
                                    .param(packet.getData()).build();
                    SocketProcess.socketIORead(client, baseSocketModel);
                }
                break;
            }

            case CLOSE:
                client.getBaseClient().onChannelDisconnect();
                break;

            default:
                break;
        }
    }
}
